Previous script: “06_get_eigengene_QTL.Rmd”

The goal is to find QTL peaks for the WGCNA eigen genes and see if those overalp with any growth QTL. We are only focusing on eigen genes that correlated with some growth traits/paramters.

library(qtl)
library(tidyverse)
── Attaching packages ────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 2.2.1     ✔ purrr   0.2.4
✔ tibble  1.3.4     ✔ dplyr   0.7.4
✔ tidyr   0.7.2     ✔ stringr 1.3.0
✔ readr   1.1.1     ✔ forcats 0.2.0
package ‘stringr’ was built under R version 3.4.3── Conflicts ───────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(stringr)
load("../output/scanone-eigengene-qtl_2012.RData")

scanone imp

Plot QTL

threshold.95 <- tibble(perm.threshold=lod.thrs[5,],
                       trait=colnames(lod.thrs))
scanone.gather <- scanone_eigen %>%
  gather(key = trait, value = LOD, -chr, -pos) %>%
  mutate(condition=str_sub(trait,1,2), color=str_sub(trait,6,100)) %>%
  left_join(threshold.95)
Joining, by = "trait"
scanone.gather
   pl.UN <- scanone.gather %>% filter(condition=="UN") %>%
  ggplot(aes(x=pos,y=LOD)) +
  geom_line() +
  geom_hline(aes(yintercept=perm.threshold),lty=2,lwd=.5,alpha=.5) +
  facet_grid(trait ~ chr, scales="free") +
  theme(strip.text.y = element_text(angle=0), axis.text.x = element_text(angle=90)) +
  ggtitle("UN Eigen Gene QTL")
pl.UN
ggsave("../output/eigen gene eQTL UN 2012.pdf",width=12,height=8)

Look for overlap

For each eigen gene, find QTL borders and look for overlap with growth QTL

For each eigen gene first identify chromosomes with “significant” peaks (in this case > 99% permuation threshold) and then runs bayesint() on them to define the intervals

sig.chrs <- scanone.gather %>% filter(LOD > perm.threshold) %>%
  group_by(trait,chr) %>%
  summarize(unique(chr))
sig.chrs

now for each significant chromosome/trait combo run bayesint

bayesint.list <- apply(sig.chrs,1,function(hit) {
    result <- bayesint(scanone_eigen[c("chr","pos",hit["trait"])], 
                     chr=hit["chr"], 
                     lodcolumn = 1,
                     expandtomarkers = TRUE
  )
  colnames(result)[3] <- "LOD"
  result
})
names(bayesint.list) <- sig.chrs$trait
bayesint.list <- lapply(bayesint.list,function(x) x %>% 
                          as.data.frame() %>%
                          rownames_to_column(var="markername")  %>%
                          mutate(chr=as.character(chr))
)
bayesint.result <- as.tibble(bind_rows(bayesint.list,.id="trait")) %>% 
  select(trait,chr,pos,markername,LOD) %>%
  separate(markername,into=c("chr1","Mbp"),sep="x", convert=TRUE) %>%
  group_by(trait,chr) %>% 
  summarize(start=min(Mbp),end=max(Mbp),min_eQTL_LOD=min(LOD),max_eQTL_LOD=max(LOD)) %>% 
  #for the high QTL peaks the interval width is 0.  That is overly precise and need to widen those.
  mutate(start=ifelse(start==end,max(0,start-20000),start), end=ifelse(start==end,end+20000,end))
Too few values at 3 locations: 20, 35, 38
  
  
bayesint.result

annotate Eigen gene QTL

Load annotation

BrapaAnnotation <- read_csv("../input/Brapa_V1.5_annotated.csv")
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_integer(),
  name = col_character(),
  chrom = col_character(),
  start = col_integer(),
  end = col_integer(),
  subject = col_character(),
  AGI = col_character(),
  At_symbol = col_character(),
  At_description = col_character(),
  perc_ID = col_double(),
  aln_length = col_integer(),
  mismatch = col_integer(),
  gap_open = col_integer(),
  qstart = col_integer(),
  qend = col_integer(),
  sstart = col_integer(),
  send = col_integer(),
  eval = col_double(),
  score = col_double()
)
BrapaAnnotation
eigen.annotated <- lapply(1:nrow(bayesint.result),function(row) {
  qtl <- bayesint.result[row,]
  results <- subset(BrapaAnnotation, chrom==qtl$chr &
                    start >= qtl$start &
                    end <= qtl$end)
}
)
names(eigen.annotated) <- bayesint.result$trait
eigen.annotated <- bind_rows(eigen.annotated,.id="trait") %>%
  mutate(chrom=as.character(chrom)) %>%
  left_join(bayesint.result,by=c("trait","chrom"="chr")) %>% #get eQTL LOD
  rename(eigen_eQTL_candidate=name)
eigen.annotated.small <- eigen.annotated %>% select(trait,eigen_eQTL_candidate,ends_with("LOD"))
eigen.annotated.small

given bayesint results, find overlaps with UN growth QTL

QTLgenes <- read_csv("../input/Bayesian2012Height_genesunderQTLS.csv")[,-1] #genes under height QTL peaks
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  .default = col_integer(),
  .id = col_character(),
  FVTtrait = col_character(),
  name = col_character(),
  chrom = col_character(),
  subject = col_character(),
  AGI = col_character(),
  At_symbol = col_character(),
  At_description = col_character(),
  perc_ID = col_double(),
  eval = col_double(),
  score = col_double()
)
See spec(...) for full column specifications.
QTLgenes
eigen.qtl.combined <- inner_join(eigen.annotated.small,QTLgenes,by=c("eigen_eQTL_candidate"="name")) %>%
  select(.id, trait, everything())
eigen.qtl.combined

how many QTL have at least some overlap?

sort(unique(QTLgenes$.id))
[1] "QTL1" "QTL2" "QTL3" "QTL4" "QTL5" "QTL6" "QTL7" "QTL8" "QTL9"
sort(unique(eigen.qtl.combined$.id))
[1] "QTL1" "QTL2" "QTL4" "QTL6" "QTL7" "QTL8" "QTL9"

All

are all eigen genes overlapping?

unique(eigen.annotated.small$trait)
[1] "UN_MEblue"          "UN_MEbrown"         "UN_MEcyan"         
[4] "UN_MEdarkslateblue" "UN_MEmidnightblue"  "UN_MEpurple"       
[7] "UN_MEturquoise"     "UN_MEyellow"        "UN_MEyellowgreen"  
unique(eigen.qtl.combined$trait)
[1] "UN_MEblue"          "UN_MEbrown"         "UN_MEcyan"         
[4] "UN_MEdarkslateblue" "UN_MEmidnightblue"  "UN_MEpurple"       
[7] "UN_MEturquoise"     "UN_MEyellow"       

No, 8 of 10

write_csv(eigen.qtl.combined,"../output/Bayesian2012Height_genesunderQTLS_eigenQTL_overlap.csv")

cim

Plot QTL

threshold.95 <- tibble(perm.threshold=lod.thrs.cim[5,],
                       trait=colnames(lod.thrs.cim))
scanone.gather <- scanone_eigen_cim %>%
  gather(key = trait, value = LOD, -chr, -pos) %>%
  mutate(condition=str_sub(trait,1,2), color=str_sub(trait,6,100)) %>%
  left_join(threshold.95)
Joining, by = "trait"
scanone.gather
   pl.UN <- scanone.gather %>% filter(condition=="UN") %>%
  ggplot(aes(x=pos,y=LOD)) +
  geom_line() +
  geom_hline(aes(yintercept=perm.threshold),lty=2,lwd=.5,alpha=.5) +
  facet_grid(trait ~ chr, scales="free") +
  theme(strip.text.y = element_text(angle=0), axis.text.x = element_text(angle=90)) +
  ggtitle("UN Eigen Gene QTL")
pl.UN
ggsave("../output/eigen gene eQTL UN CIM 2012.pdf",width=12,height=8)

Look for overlap

For each eigen gene, find QTL borders and look for overlap with growth QTL

For each eigen gene first identify chromosomes with “significant” peaks (in this case > 99% permuation threshold) and then runs bayesint() on them to define the intervals

sig.chrs <- scanone.gather %>% filter(LOD > perm.threshold) %>%
  group_by(trait,chr) %>%
  summarize(unique(chr))
sig.chrs

now for each significant chromosome/trait combo run bayesint

bayesint.list <- apply(sig.chrs,1,function(hit) {
    result <- bayesint(scanone_eigen[c("chr","pos",hit["trait"])], 
                     chr=hit["chr"], 
                     lodcolumn = 1,
                     expandtomarkers = TRUE
  )
  colnames(result)[3] <- "LOD"
  result
})
names(bayesint.list) <- sig.chrs$trait
bayesint.list <- lapply(bayesint.list,function(x) x %>% 
                          as.data.frame() %>%
                          rownames_to_column(var="markername")  %>%
                          mutate(chr=as.character(chr))
)
bayesint.result <- as.tibble(bind_rows(bayesint.list,.id="trait")) %>% 
  select(trait,chr,pos,markername,LOD) %>%
  separate(markername,into=c("chr1","Mbp"),sep="x", convert=TRUE) %>%
  group_by(trait,chr) %>% 
  summarize(start=min(Mbp),end=max(Mbp),min_eQTL_LOD=min(LOD),max_eQTL_LOD=max(LOD)) %>% 
  #for the high QTL peaks the interval width is 0.  That is overly precise and need to widen those.
  mutate(start=ifelse(start==end,max(0,start-20000),start), end=ifelse(start==end,end+20000,end))
Too few values at 2 locations: 17, 26
  
  
bayesint.result

annotate Eigen gene QTL

Load annotation

BrapaAnnotation <- read_csv("../input/Brapa_V1.5_annotated.csv")
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_integer(),
  name = col_character(),
  chrom = col_character(),
  start = col_integer(),
  end = col_integer(),
  subject = col_character(),
  AGI = col_character(),
  At_symbol = col_character(),
  At_description = col_character(),
  perc_ID = col_double(),
  aln_length = col_integer(),
  mismatch = col_integer(),
  gap_open = col_integer(),
  qstart = col_integer(),
  qend = col_integer(),
  sstart = col_integer(),
  send = col_integer(),
  eval = col_double(),
  score = col_double()
)
BrapaAnnotation
eigen.annotated <- lapply(1:nrow(bayesint.result),function(row) {
  qtl <- bayesint.result[row,]
  results <- subset(BrapaAnnotation, chrom==qtl$chr &
                    start >= qtl$start &
                    end <= qtl$end)
}
)
names(eigen.annotated) <- bayesint.result$trait
eigen.annotated <- bind_rows(eigen.annotated,.id="trait") %>%
  mutate(chrom=as.character(chrom)) %>%
  left_join(bayesint.result,by=c("trait","chrom"="chr")) %>% #get eQTL LOD
  rename(eigen_eQTL_candidate=name)
eigen.annotated.small <- eigen.annotated %>% select(trait,eigen_eQTL_candidate,ends_with("LOD"))
eigen.annotated.small

given bayesint results, find overlaps with UN growth QTL

QTLgenes <- read_csv("../input/Bayesian2012Height_genesunderQTLS.csv")[,-1] #genes under height QTL peaks
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  .default = col_integer(),
  .id = col_character(),
  FVTtrait = col_character(),
  name = col_character(),
  chrom = col_character(),
  subject = col_character(),
  AGI = col_character(),
  At_symbol = col_character(),
  At_description = col_character(),
  perc_ID = col_double(),
  eval = col_double(),
  score = col_double()
)
See spec(...) for full column specifications.
QTLgenes
eigen.qtl.combined <- inner_join(eigen.annotated.small,QTLgenes,by=c("eigen_eQTL_candidate"="name")) %>%
  select(.id, trait, everything())
eigen.qtl.combined

how many QTL have at least some overlap?

unique(QTLgenes$.id)
[1] "QTL1" "QTL2" "QTL3" "QTL4" "QTL5" "QTL6" "QTL7" "QTL8" "QTL9"
unique(eigen.qtl.combined$.id)
[1] "QTL9" "QTL2" "QTL4" "QTL6" "QTL7" "QTL8" "QTL1"

seven of nine

are all eigen genes overlapping?

unique(eigen.annotated.small$trait)
[1] "UN_MEblue"          "UN_MEbrown"         "UN_MEcyan"         
[4] "UN_MEdarkslateblue" "UN_MEmidnightblue"  "UN_MEturquoise"    
[7] "UN_MEyellowgreen"  
unique(eigen.qtl.combined$trait)
[1] "UN_MEbrown"         "UN_MEcyan"          "UN_MEdarkslateblue"
[4] "UN_MEmidnightblue"  "UN_MEturquoise"    

No, 5

write_csv(eigen.qtl.combined,"../output/Bayesian2012Height_genesunderQTLS_eigenQTL_overlap_CIM.csv")
LS0tCnRpdGxlOiAiQW5hbHl6ZSBFaWdlbiBHZW5lIFFUTCIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogIkp1bGluIE1hbG9vZiIKLS0tCgoKUHJldmlvdXMgc2NyaXB0OiAiMDZfZ2V0X2VpZ2VuZ2VuZV9RVEwuUm1kIgoKVGhlIGdvYWwgaXMgdG8gZmluZCBRVEwgcGVha3MgZm9yIHRoZSBXR0NOQSBlaWdlbiBnZW5lcyBhbmQgc2VlIGlmIHRob3NlIG92ZXJhbHAgd2l0aCBhbnkgZ3Jvd3RoIFFUTC4gIFdlIGFyZSBvbmx5IGZvY3VzaW5nIG9uIGVpZ2VuIGdlbmVzIHRoYXQgY29ycmVsYXRlZCB3aXRoIHNvbWUgZ3Jvd3RoIHRyYWl0cy9wYXJhbXRlcnMuCgpgYGB7cn0KbGlicmFyeShxdGwpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHN0cmluZ3IpCmxvYWQoIi4uL291dHB1dC9zY2Fub25lLWVpZ2VuZ2VuZS1xdGxfMjAxMi5SRGF0YSIpCmBgYAoKIyBzY2Fub25lIGltcAoKIyMgUGxvdCBRVEwKCmBgYHtyfQoKdGhyZXNob2xkLjk1IDwtIHRpYmJsZShwZXJtLnRocmVzaG9sZD1sb2QudGhyc1s1LF0sCiAgICAgICAgICAgICAgICAgICAgICAgdHJhaXQ9Y29sbmFtZXMobG9kLnRocnMpKQoKc2Nhbm9uZS5nYXRoZXIgPC0gc2Nhbm9uZV9laWdlbiAlPiUKICBnYXRoZXIoa2V5ID0gdHJhaXQsIHZhbHVlID0gTE9ELCAtY2hyLCAtcG9zKSAlPiUKICBtdXRhdGUoY29uZGl0aW9uPXN0cl9zdWIodHJhaXQsMSwyKSwgY29sb3I9c3RyX3N1Yih0cmFpdCw2LDEwMCkpICU+JQogIGxlZnRfam9pbih0aHJlc2hvbGQuOTUpCgpzY2Fub25lLmdhdGhlcgpgYGAKCmBgYHtyfQogICBwbC5VTiA8LSBzY2Fub25lLmdhdGhlciAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IlVOIikgJT4lCiAgZ2dwbG90KGFlcyh4PXBvcyx5PUxPRCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD1wZXJtLnRocmVzaG9sZCksbHR5PTIsbHdkPS41LGFscGhhPS41KSArCiAgZmFjZXRfZ3JpZCh0cmFpdCB+IGNociwgc2NhbGVzPSJmcmVlIikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZT0wKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApKSArCiAgZ2d0aXRsZSgiVU4gRWlnZW4gR2VuZSBRVEwiKQpwbC5VTgpnZ3NhdmUoIi4uL291dHB1dC9laWdlbiBnZW5lIGVRVEwgVU4gMjAxMi5wZGYiLHdpZHRoPTEyLGhlaWdodD04KQpgYGAKCgojIyBMb29rIGZvciBvdmVybGFwCgpGb3IgZWFjaCBlaWdlbiBnZW5lLCBmaW5kIFFUTCBib3JkZXJzIGFuZCBsb29rIGZvciBvdmVybGFwIHdpdGggZ3Jvd3RoIFFUTAoKRm9yIGVhY2ggZWlnZW4gZ2VuZSBmaXJzdCBpZGVudGlmeSBjaHJvbW9zb21lcyB3aXRoICJzaWduaWZpY2FudCIgcGVha3MgKGluIHRoaXMgY2FzZSA+IDk5JSBwZXJtdWF0aW9uIHRocmVzaG9sZCkgYW5kIHRoZW4gcnVucyBiYXllc2ludCgpIG9uIHRoZW0gdG8gZGVmaW5lIHRoZSBpbnRlcnZhbHMKCmBgYHtyfQpzaWcuY2hycyA8LSBzY2Fub25lLmdhdGhlciAlPiUgZmlsdGVyKExPRCA+IHBlcm0udGhyZXNob2xkKSAlPiUKICBncm91cF9ieSh0cmFpdCxjaHIpICU+JQogIHN1bW1hcml6ZSh1bmlxdWUoY2hyKSkKc2lnLmNocnMKYGBgCgpub3cgZm9yIGVhY2ggc2lnbmlmaWNhbnQgY2hyb21vc29tZS90cmFpdCBjb21ibyBydW4gYmF5ZXNpbnQKCmBgYHtyfQpiYXllc2ludC5saXN0IDwtIGFwcGx5KHNpZy5jaHJzLDEsZnVuY3Rpb24oaGl0KSB7CiAgICByZXN1bHQgPC0gYmF5ZXNpbnQoc2Nhbm9uZV9laWdlbltjKCJjaHIiLCJwb3MiLGhpdFsidHJhaXQiXSldLCAKICAgICAgICAgICAgICAgICAgICAgY2hyPWhpdFsiY2hyIl0sIAogICAgICAgICAgICAgICAgICAgICBsb2Rjb2x1bW4gPSAxLAogICAgICAgICAgICAgICAgICAgICBleHBhbmR0b21hcmtlcnMgPSBUUlVFCiAgKQogIGNvbG5hbWVzKHJlc3VsdClbM10gPC0gIkxPRCIKICByZXN1bHQKfSkKCm5hbWVzKGJheWVzaW50Lmxpc3QpIDwtIHNpZy5jaHJzJHRyYWl0CgpiYXllc2ludC5saXN0IDwtIGxhcHBseShiYXllc2ludC5saXN0LGZ1bmN0aW9uKHgpIHggJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4odmFyPSJtYXJrZXJuYW1lIikgICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShjaHI9YXMuY2hhcmFjdGVyKGNocikpCikKCmJheWVzaW50LnJlc3VsdCA8LSBhcy50aWJibGUoYmluZF9yb3dzKGJheWVzaW50Lmxpc3QsLmlkPSJ0cmFpdCIpKSAlPiUgCiAgc2VsZWN0KHRyYWl0LGNocixwb3MsbWFya2VybmFtZSxMT0QpICU+JQogIHNlcGFyYXRlKG1hcmtlcm5hbWUsaW50bz1jKCJjaHIxIiwiTWJwIiksc2VwPSJ4IiwgY29udmVydD1UUlVFKSAlPiUKICBncm91cF9ieSh0cmFpdCxjaHIpICU+JSAKICBzdW1tYXJpemUoc3RhcnQ9bWluKE1icCksZW5kPW1heChNYnApLG1pbl9lUVRMX0xPRD1taW4oTE9EKSxtYXhfZVFUTF9MT0Q9bWF4KExPRCkpICU+JSAKICAjZm9yIHRoZSBoaWdoIFFUTCBwZWFrcyB0aGUgaW50ZXJ2YWwgd2lkdGggaXMgMC4gIFRoYXQgaXMgb3Zlcmx5IHByZWNpc2UgYW5kIG5lZWQgdG8gd2lkZW4gdGhvc2UuCiAgbXV0YXRlKHN0YXJ0PWlmZWxzZShzdGFydD09ZW5kLG1heCgwLHN0YXJ0LTIwMDAwKSxzdGFydCksIGVuZD1pZmVsc2Uoc3RhcnQ9PWVuZCxlbmQrMjAwMDAsZW5kKSkKICAKICAKYmF5ZXNpbnQucmVzdWx0CmBgYAoKIyMjIGFubm90YXRlIEVpZ2VuIGdlbmUgUVRMCgpMb2FkIGFubm90YXRpb24KYGBge3J9CkJyYXBhQW5ub3RhdGlvbiA8LSByZWFkX2NzdigiLi4vaW5wdXQvQnJhcGFfVjEuNV9hbm5vdGF0ZWQuY3N2IikKQnJhcGFBbm5vdGF0aW9uCmBgYAoKYGBge3J9CmVpZ2VuLmFubm90YXRlZCA8LSBsYXBwbHkoMTpucm93KGJheWVzaW50LnJlc3VsdCksZnVuY3Rpb24ocm93KSB7CiAgcXRsIDwtIGJheWVzaW50LnJlc3VsdFtyb3csXQogIHJlc3VsdHMgPC0gc3Vic2V0KEJyYXBhQW5ub3RhdGlvbiwgY2hyb209PXF0bCRjaHIgJgogICAgICAgICAgICAgICAgICAgIHN0YXJ0ID49IHF0bCRzdGFydCAmCiAgICAgICAgICAgICAgICAgICAgZW5kIDw9IHF0bCRlbmQpCn0KKQpuYW1lcyhlaWdlbi5hbm5vdGF0ZWQpIDwtIGJheWVzaW50LnJlc3VsdCR0cmFpdAoKZWlnZW4uYW5ub3RhdGVkIDwtIGJpbmRfcm93cyhlaWdlbi5hbm5vdGF0ZWQsLmlkPSJ0cmFpdCIpICU+JQogIG11dGF0ZShjaHJvbT1hcy5jaGFyYWN0ZXIoY2hyb20pKSAlPiUKICBsZWZ0X2pvaW4oYmF5ZXNpbnQucmVzdWx0LGJ5PWMoInRyYWl0IiwiY2hyb20iPSJjaHIiKSkgJT4lICNnZXQgZVFUTCBMT0QKICByZW5hbWUoZWlnZW5fZVFUTF9jYW5kaWRhdGU9bmFtZSkKCmVpZ2VuLmFubm90YXRlZC5zbWFsbCA8LSBlaWdlbi5hbm5vdGF0ZWQgJT4lIHNlbGVjdCh0cmFpdCxlaWdlbl9lUVRMX2NhbmRpZGF0ZSxlbmRzX3dpdGgoIkxPRCIpKQoKZWlnZW4uYW5ub3RhdGVkLnNtYWxsCmBgYAoKZ2l2ZW4gYmF5ZXNpbnQgcmVzdWx0cywgZmluZCBvdmVybGFwcyB3aXRoIFVOIGdyb3d0aCBRVEwKCmBgYHtyfQpRVExnZW5lcyA8LSByZWFkX2NzdigiLi4vaW5wdXQvQmF5ZXNpYW4yMDEySGVpZ2h0X2dlbmVzdW5kZXJRVExTLmNzdiIpWywtMV0gI2dlbmVzIHVuZGVyIGhlaWdodCBRVEwgcGVha3MKUVRMZ2VuZXMKYGBgCgpgYGB7cn0KZWlnZW4ucXRsLmNvbWJpbmVkIDwtIGlubmVyX2pvaW4oZWlnZW4uYW5ub3RhdGVkLnNtYWxsLFFUTGdlbmVzLGJ5PWMoImVpZ2VuX2VRVExfY2FuZGlkYXRlIj0ibmFtZSIpKSAlPiUKICBzZWxlY3QoLmlkLCB0cmFpdCwgZXZlcnl0aGluZygpKQplaWdlbi5xdGwuY29tYmluZWQKYGBgCgpob3cgbWFueSBRVEwgaGF2ZSBhdCBsZWFzdCBzb21lIG92ZXJsYXA/CmBgYHtyfQpzb3J0KHVuaXF1ZShRVExnZW5lcyQuaWQpKQpzb3J0KHVuaXF1ZShlaWdlbi5xdGwuY29tYmluZWQkLmlkKSkKYGBgCgpBbGwKCmFyZSBhbGwgZWlnZW4gZ2VuZXMgb3ZlcmxhcHBpbmc/CgpgYGB7cn0KdW5pcXVlKGVpZ2VuLmFubm90YXRlZC5zbWFsbCR0cmFpdCkKdW5pcXVlKGVpZ2VuLnF0bC5jb21iaW5lZCR0cmFpdCkKYGBgCgpObywgOCBvZiAxMAoKYGBge3J9CndyaXRlX2NzdihlaWdlbi5xdGwuY29tYmluZWQsIi4uL291dHB1dC9CYXllc2lhbjIwMTJIZWlnaHRfZ2VuZXN1bmRlclFUTFNfZWlnZW5RVExfb3ZlcmxhcC5jc3YiKQpgYGAKCiMgY2ltCgojIyBQbG90IFFUTAoKYGBge3J9Cgp0aHJlc2hvbGQuOTUgPC0gdGliYmxlKHBlcm0udGhyZXNob2xkPWxvZC50aHJzLmNpbVs1LF0sCiAgICAgICAgICAgICAgICAgICAgICAgdHJhaXQ9Y29sbmFtZXMobG9kLnRocnMuY2ltKSkKCnNjYW5vbmUuZ2F0aGVyIDwtIHNjYW5vbmVfZWlnZW5fY2ltICU+JQogIGdhdGhlcihrZXkgPSB0cmFpdCwgdmFsdWUgPSBMT0QsIC1jaHIsIC1wb3MpICU+JQogIG11dGF0ZShjb25kaXRpb249c3RyX3N1Yih0cmFpdCwxLDIpLCBjb2xvcj1zdHJfc3ViKHRyYWl0LDYsMTAwKSkgJT4lCiAgbGVmdF9qb2luKHRocmVzaG9sZC45NSkKCnNjYW5vbmUuZ2F0aGVyCmBgYAoKYGBge3J9CiAgIHBsLlVOIDwtIHNjYW5vbmUuZ2F0aGVyICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iVU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cG9zLHk9TE9EKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PXBlcm0udGhyZXNob2xkKSxsdHk9Mixsd2Q9LjUsYWxwaGE9LjUpICsKICBmYWNldF9ncmlkKHRyYWl0IH4gY2hyLCBzY2FsZXM9ImZyZWUiKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCkpICsKICBnZ3RpdGxlKCJVTiBFaWdlbiBHZW5lIFFUTCIpCnBsLlVOCmdnc2F2ZSgiLi4vb3V0cHV0L2VpZ2VuIGdlbmUgZVFUTCBVTiBDSU0gMjAxMi5wZGYiLHdpZHRoPTEyLGhlaWdodD04KQpgYGAKCgojIyBMb29rIGZvciBvdmVybGFwCgpGb3IgZWFjaCBlaWdlbiBnZW5lLCBmaW5kIFFUTCBib3JkZXJzIGFuZCBsb29rIGZvciBvdmVybGFwIHdpdGggZ3Jvd3RoIFFUTAoKRm9yIGVhY2ggZWlnZW4gZ2VuZSBmaXJzdCBpZGVudGlmeSBjaHJvbW9zb21lcyB3aXRoICJzaWduaWZpY2FudCIgcGVha3MgKGluIHRoaXMgY2FzZSA+IDk5JSBwZXJtdWF0aW9uIHRocmVzaG9sZCkgYW5kIHRoZW4gcnVucyBiYXllc2ludCgpIG9uIHRoZW0gdG8gZGVmaW5lIHRoZSBpbnRlcnZhbHMKCmBgYHtyfQpzaWcuY2hycyA8LSBzY2Fub25lLmdhdGhlciAlPiUgZmlsdGVyKExPRCA+IHBlcm0udGhyZXNob2xkKSAlPiUKICBncm91cF9ieSh0cmFpdCxjaHIpICU+JQogIHN1bW1hcml6ZSh1bmlxdWUoY2hyKSkKc2lnLmNocnMKYGBgCgpub3cgZm9yIGVhY2ggc2lnbmlmaWNhbnQgY2hyb21vc29tZS90cmFpdCBjb21ibyBydW4gYmF5ZXNpbnQKCmBgYHtyfQpiYXllc2ludC5saXN0IDwtIGFwcGx5KHNpZy5jaHJzLDEsZnVuY3Rpb24oaGl0KSB7CiAgICByZXN1bHQgPC0gYmF5ZXNpbnQoc2Nhbm9uZV9laWdlbltjKCJjaHIiLCJwb3MiLGhpdFsidHJhaXQiXSldLCAKICAgICAgICAgICAgICAgICAgICAgY2hyPWhpdFsiY2hyIl0sIAogICAgICAgICAgICAgICAgICAgICBsb2Rjb2x1bW4gPSAxLAogICAgICAgICAgICAgICAgICAgICBleHBhbmR0b21hcmtlcnMgPSBUUlVFCiAgKQogIGNvbG5hbWVzKHJlc3VsdClbM10gPC0gIkxPRCIKICByZXN1bHQKfSkKCm5hbWVzKGJheWVzaW50Lmxpc3QpIDwtIHNpZy5jaHJzJHRyYWl0CgpiYXllc2ludC5saXN0IDwtIGxhcHBseShiYXllc2ludC5saXN0LGZ1bmN0aW9uKHgpIHggJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4odmFyPSJtYXJrZXJuYW1lIikgICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShjaHI9YXMuY2hhcmFjdGVyKGNocikpCikKCmJheWVzaW50LnJlc3VsdCA8LSBhcy50aWJibGUoYmluZF9yb3dzKGJheWVzaW50Lmxpc3QsLmlkPSJ0cmFpdCIpKSAlPiUgCiAgc2VsZWN0KHRyYWl0LGNocixwb3MsbWFya2VybmFtZSxMT0QpICU+JQogIHNlcGFyYXRlKG1hcmtlcm5hbWUsaW50bz1jKCJjaHIxIiwiTWJwIiksc2VwPSJ4IiwgY29udmVydD1UUlVFKSAlPiUKICBncm91cF9ieSh0cmFpdCxjaHIpICU+JSAKICBzdW1tYXJpemUoc3RhcnQ9bWluKE1icCksZW5kPW1heChNYnApLG1pbl9lUVRMX0xPRD1taW4oTE9EKSxtYXhfZVFUTF9MT0Q9bWF4KExPRCkpICU+JSAKICAjZm9yIHRoZSBoaWdoIFFUTCBwZWFrcyB0aGUgaW50ZXJ2YWwgd2lkdGggaXMgMC4gIFRoYXQgaXMgb3Zlcmx5IHByZWNpc2UgYW5kIG5lZWQgdG8gd2lkZW4gdGhvc2UuCiAgbXV0YXRlKHN0YXJ0PWlmZWxzZShzdGFydD09ZW5kLG1heCgwLHN0YXJ0LTIwMDAwKSxzdGFydCksIGVuZD1pZmVsc2Uoc3RhcnQ9PWVuZCxlbmQrMjAwMDAsZW5kKSkKICAKICAKYmF5ZXNpbnQucmVzdWx0CmBgYAoKIyMjIGFubm90YXRlIEVpZ2VuIGdlbmUgUVRMCgpMb2FkIGFubm90YXRpb24KYGBge3J9CkJyYXBhQW5ub3RhdGlvbiA8LSByZWFkX2NzdigiLi4vaW5wdXQvQnJhcGFfVjEuNV9hbm5vdGF0ZWQuY3N2IikKQnJhcGFBbm5vdGF0aW9uCmBgYAoKYGBge3J9CmVpZ2VuLmFubm90YXRlZCA8LSBsYXBwbHkoMTpucm93KGJheWVzaW50LnJlc3VsdCksZnVuY3Rpb24ocm93KSB7CiAgcXRsIDwtIGJheWVzaW50LnJlc3VsdFtyb3csXQogIHJlc3VsdHMgPC0gc3Vic2V0KEJyYXBhQW5ub3RhdGlvbiwgY2hyb209PXF0bCRjaHIgJgogICAgICAgICAgICAgICAgICAgIHN0YXJ0ID49IHF0bCRzdGFydCAmCiAgICAgICAgICAgICAgICAgICAgZW5kIDw9IHF0bCRlbmQpCn0KKQpuYW1lcyhlaWdlbi5hbm5vdGF0ZWQpIDwtIGJheWVzaW50LnJlc3VsdCR0cmFpdAoKZWlnZW4uYW5ub3RhdGVkIDwtIGJpbmRfcm93cyhlaWdlbi5hbm5vdGF0ZWQsLmlkPSJ0cmFpdCIpICU+JQogIG11dGF0ZShjaHJvbT1hcy5jaGFyYWN0ZXIoY2hyb20pKSAlPiUKICBsZWZ0X2pvaW4oYmF5ZXNpbnQucmVzdWx0LGJ5PWMoInRyYWl0IiwiY2hyb20iPSJjaHIiKSkgJT4lICNnZXQgZVFUTCBMT0QKICByZW5hbWUoZWlnZW5fZVFUTF9jYW5kaWRhdGU9bmFtZSkKCmVpZ2VuLmFubm90YXRlZC5zbWFsbCA8LSBlaWdlbi5hbm5vdGF0ZWQgJT4lIHNlbGVjdCh0cmFpdCxlaWdlbl9lUVRMX2NhbmRpZGF0ZSxlbmRzX3dpdGgoIkxPRCIpKQoKZWlnZW4uYW5ub3RhdGVkLnNtYWxsCmBgYAoKZ2l2ZW4gYmF5ZXNpbnQgcmVzdWx0cywgZmluZCBvdmVybGFwcyB3aXRoIFVOIGdyb3d0aCBRVEwKCmBgYHtyfQpRVExnZW5lcyA8LSByZWFkX2NzdigiLi4vaW5wdXQvQmF5ZXNpYW4yMDEySGVpZ2h0X2dlbmVzdW5kZXJRVExTLmNzdiIpWywtMV0gI2dlbmVzIHVuZGVyIGhlaWdodCBRVEwgcGVha3MKUVRMZ2VuZXMKYGBgCgpgYGB7cn0KZWlnZW4ucXRsLmNvbWJpbmVkIDwtIGlubmVyX2pvaW4oZWlnZW4uYW5ub3RhdGVkLnNtYWxsLFFUTGdlbmVzLGJ5PWMoImVpZ2VuX2VRVExfY2FuZGlkYXRlIj0ibmFtZSIpKSAlPiUKICBzZWxlY3QoLmlkLCB0cmFpdCwgZXZlcnl0aGluZygpKQplaWdlbi5xdGwuY29tYmluZWQKYGBgCgpob3cgbWFueSBRVEwgaGF2ZSBhdCBsZWFzdCBzb21lIG92ZXJsYXA/CmBgYHtyfQp1bmlxdWUoUVRMZ2VuZXMkLmlkKQp1bmlxdWUoZWlnZW4ucXRsLmNvbWJpbmVkJC5pZCkKYGBgCgpzZXZlbiBvZiBuaW5lCgphcmUgYWxsIGVpZ2VuIGdlbmVzIG92ZXJsYXBwaW5nPwoKYGBge3J9CnVuaXF1ZShlaWdlbi5hbm5vdGF0ZWQuc21hbGwkdHJhaXQpCnVuaXF1ZShlaWdlbi5xdGwuY29tYmluZWQkdHJhaXQpCmBgYAoKTm8sIDUKCmBgYHtyfQp3cml0ZV9jc3YoZWlnZW4ucXRsLmNvbWJpbmVkLCIuLi9vdXRwdXQvQmF5ZXNpYW4yMDEySGVpZ2h0X2dlbmVzdW5kZXJRVExTX2VpZ2VuUVRMX292ZXJsYXBfQ0lNLmNzdiIpCmBgYAoK